package yf.mall.service.impl;

import com.github.pagehelper.PageHelper;
import com.yf.service.WxPayService;
import com.yf.utils.DateUtil;
import org.springframework.stereotype.Service;
import yf.mall.common.Const;
import yf.mall.dao.*;
import yf.mall.entity.*;
import com.yf.service.impl.BaseServiceImpl;
import yf.mall.enums.*;
import com.yf.response.RRException;
import yf.mall.service.*;
import yf.mall.vo.AccountRecordVo;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import org.springframework.transaction.annotation.Transactional;
import yf.mall.vo.OrderItemVo;

/**
 * 账户Service实现类
 *
 * @author hxf
 * @email 505860922@qq.com
 * @date Mon Aug 26 16:58:11 CST 2019
 */
@Service
public class AccountServiceImpl extends BaseServiceImpl<AccountEntity> implements AccountService {

    private AccountDao accountDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserService userService;

    @Autowired
    private LevelService levelService;


    @Autowired
    public void setDao(AccountDao accountDao) {
        this.accountDao = accountDao;
        super.setBaseDao(accountDao);
    }


    /**内部方法**/


    /**
     * 外部方法实现
     **/

    @Autowired
    private AccountRecordDao accountRecordDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(Long fromUserId, Long toUserId, int type, BigDecimal amount, String remark) {

        if (!fromUserId.equals(Const.ADMIN_ID) && fromUserId.equals(toUserId)) {
            throw new RRException("禁止转给自己");
        }

        //经验值只允许与公司交易
        if (type == AccountTypeEnum.EXP.getIndex()) {
            if (!fromUserId.equals(Const.ADMIN_ID) && !toUserId.equals(Const.ADMIN_ID)) {
                throw new RRException("禁止交易!");
            }
        }

//        AccountEntity fromUserAccount = decrease(fromUserId, type, amount);
//        AccountEntity toUserAccount = increase(toUserId, type, amount);
        //生成记录
        AccountRecordEntity recordEntity = new AccountRecordEntity(fromUserId, toUserId, type, amount, null, null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.TRANSFER.getIndex());
        //转账
        doneTransfer(recordEntity);
        accountRecordDao.save(recordEntity);
        //通知
//        noticeAccount(recordEntity);
    }


    @Override
    public void pay(Long userId, int type, BigDecimal amount, String orderNo) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        AccountEntity userAccount = decrease(userId, type, amount);
        UserEntity userEntity = userDao.get(userId);
        String remark = userEntity.getName() + Const.BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = new AccountRecordEntity(userId, Const.ADMIN_ID, type, amount, userAccount.getAmount(), null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.PAY.getIndex());
        accountRecordDao.save(recordEntity);
        //通知
        noticeAccount(recordEntity);
    }


    @Override
    public void autoPay(Long userId, int type, BigDecimal amount, String orderNo) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        AccountEntity userAccount = decrease(userId, type, amount);
        UserEntity userEntity = userDao.get(userId);
        String remark = userEntity.getName() + Const.AUTO_BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = new AccountRecordEntity(userId, Const.ADMIN_ID, type, amount, userAccount.getAmount(), null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.AUTO_PAY.getIndex());
        accountRecordDao.save(recordEntity);
        //通知
        noticeAccount(recordEntity);
    }

    /**
     * 是否立即到账
     *
     * @param userId
     * @param amount
     * @param orderNo
     * @param name
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rewardExp(Long userId, BigDecimal amount, String orderNo, String name, boolean reward) {
        //TODO 暂时延迟到账
//        reward(userId, AccountTypeEnum.EXP.getIndex(), amount, name, orderNo, reward);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backExp(Long userId, BigDecimal amount, String orderNo, String name) {
//        String remark = name + Const.BACK_ORDER_NO + orderNo;
//        AccountRecordEntity recordEntity = new AccountRecordEntity(userId, Const.ADMIN_ID, AccountTypeEnum.EXP.getIndex(), amount, null, null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.BACK.getIndex());
//        accountRecordDao.save(recordEntity);
//        doneTransfer(recordEntity);
    }

    /**
     * 返还钱
     *
     * @param userId
     * @param type
     * @param amount
     * @param orderNo
     */
    @Transactional(rollbackFor = Exception.class)
    public void returnMoney(Long userId, int type, BigDecimal amount, String orderNo) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        AccountEntity userAccount = increase(userId, type, amount);
        UserEntity userEntity = userDao.get(userId);
        String remark = userEntity.getName() + Const.BACK_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = new AccountRecordEntity(Const.ADMIN_ID, userId, type, amount, userAccount.getAmount(), null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.BACK.getIndex());
        accountRecordDao.save(recordEntity);
        //通知
        noticeAccount(recordEntity);
    }

    @Override
    public void reward(Long userId, int type, BigDecimal amount, String name, String orderNo, Boolean isReward, Integer busType) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        Integer bus = busType;
        String remark = name + Const.BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = buildAwaitTransfer(userId, type, amount, remark, bus);
        //立即给与
        if (isReward) {
            doneTransfer(recordEntity);
        } else {
            //通知
            noticeAccount(recordEntity);
        }
    }

    /**
     * 公司给出的可以延迟到账
     *
     * @param userId
     * @param type
     * @param amount
     * @param remark
     * @return
     */
    private AccountRecordEntity buildAwaitTransfer(Long userId, int type, BigDecimal amount, String remark, int bus) {
        Long fromUserId = Const.ADMIN_ID;
        //生成记录
        AccountRecordEntity recordEntity = new AccountRecordEntity(fromUserId, userId, type, amount, null, null, new Date(), remark, AccountRecordStatusEnum.WAIT.getIndex(), bus);
        accountRecordDao.save(recordEntity);
        return recordEntity;
    }


    @Transactional(rollbackFor = Exception.class)
    public void back(Long id) {
        AccountRecordEntity recordEntity = accountRecordDao.get(id);
        //未完成直接删除
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.WAIT.getIndex())) {
            accountRecordDao.delete(id);
            return;
        }
        //已经完成的
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            BigDecimal toUserAmount = null;
            BigDecimal fromUserAmount = null;
            //生成记录
            String remark = recordEntity.getInfo().replace(Const.BUY_ORDER_NO, Const.BACK_ORDER_NO);
            if (!recordEntity.getToUserId().equals(Const.ADMIN_ID)) {
                AccountEntity userAccount = decrease(recordEntity.getToUserId(), recordEntity.getType(), recordEntity.getAmount());
                toUserAmount = userAccount.getAmount();
            }
            if (!recordEntity.getFromUserId().equals(Const.ADMIN_ID)) {
                AccountEntity userAccount = increase(recordEntity.getFromUserId(), recordEntity.getType(), recordEntity.getAmount());
                fromUserAmount = userAccount.getAmount();

            }

            AccountRecordEntity recordEntity1 = new AccountRecordEntity(recordEntity.getToUserId(), recordEntity.getFromUserId(), recordEntity.getType(), recordEntity.getAmount(), toUserAmount, fromUserAmount, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.BACK.getIndex());
            accountRecordDao.save(recordEntity1);

            //如果是退回经验值 还要改变级别
            if (recordEntity.getType() == AccountTypeEnum.EXP.getIndex()) {
                levelService.changeLevelByExp(recordEntity1.getFromUserId(), toUserAmount);
            }
            //通知
            noticeAccount(recordEntity1);
        }
    }

    @Autowired
    private MallOrderService mallOrderService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(String orderNo) {
        List<AccountRecordEntity> records = new ArrayList<>();
        //所有支付出去的券
        List<AccountRecordEntity> recordPay = findByOrderNoAndBusType(orderNo, AccountRecordBusEnum.PAY.getIndex());
        records.addAll(recordPay);
        //所有奖励的券
        List<AccountRecordEntity> recordReward = findByOrderNoAndBusType(orderNo, AccountRecordBusEnum.SHARE_REWARD.getIndex(), AccountRecordBusEnum.AREA_REWARD.getIndex());
        records.addAll(recordReward);
        //所有货款
        List<AccountRecordEntity> recordCod = findByOrderNoAndBusType(orderNo, AccountRecordBusEnum.PAYMENT.getIndex());
        records.addAll(recordCod);
        //执行退还
        records.forEach(record -> {
            back(record.getId());
        });
        //如果是其它支付 转换成现金券退回
        MallOrderEntity orderEntity = mallOrderService.findByOrderNo(orderNo);
        //进货
        if (orderEntity.getBusType() == MallOrderBusTypeEnum.BUY.getIndex() && orderEntity.getPayStatus() == MallOrderPayStatusEnum.PAID.getIndex() && MallOrderPayWayEnum.WX.getIndex() == orderEntity.getPayWay()) {
            //有钱可以退
            if (mallOrderService.getRetailPrice(orderEntity).compareTo(BigDecimal.ZERO) > 0) {
                returnMoney(orderEntity.getUserId(), AccountTypeEnum.CASH.getIndex(), mallOrderService.getRetailPrice(orderEntity), orderNo);
            }
        }
    }


    /**
     * 完成一个订单相关的所有转账
     *
     * @param orderNo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doneTransfer(String orderNo) {
        List<AccountRecordEntity> accountRecordEntities = this.accountRecordDao.findByOrderNos("%" + orderNo + "%", AccountRecordStatusEnum.WAIT.getIndex());
        accountRecordEntities.forEach(accountRecordEntity -> {
            if (accountRecordEntity.getStatus().equals(AccountRecordStatusEnum.WAIT.getIndex())) {
                doneTransfer(accountRecordEntity);
            }
//            noticeAccount(accountRecordEntity);
        });
    }

    /**
     * 完成一条未完成记录的转账
     *
     * @param accountRecordEntity
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doneTransfer(AccountRecordEntity accountRecordEntity) {
        BigDecimal amount = accountRecordEntity.getAmount();
        AccountEntity fromUserAccount = decrease(accountRecordEntity.getFromUserId(), accountRecordEntity.getType(), amount);
        AccountEntity toUserAccount = increase(accountRecordEntity.getToUserId(), accountRecordEntity.getType(), amount);
        int type = accountRecordEntity.getType();
        //如果是转经验值  经验值只有跟公司之间的转让
        if (AccountTypeEnum.EXP.getIndex() == type) {
            LevelEntity fl = levelDao.findByUserId(fromUserAccount.getUserId());
            LevelEntity tl = levelDao.findByUserId(toUserAccount.getUserId());
            //公司转出的
            if (fromUserAccount.getUserId().equals(Const.ADMIN_ID)) {
                //转出经验值 接收人的经验值比自己的还高了
                levelService.changeLevelByExp(toUserAccount.getUserId(), toUserAccount.getAmount());
            }

            if (toUserAccount.getUserId().equals(Const.ADMIN_ID)) { //转给公司的
                //转出经验值 接收人的经验值比自己的还高了
                levelService.changeLevelByExp(fromUserAccount.getUserId(), fromUserAccount.getAmount());
            }
        }
        accountRecordEntity.setFromNowAmount(fromUserAccount.getAmount());
        accountRecordEntity.setToNowAmount(toUserAccount.getAmount());
        accountRecordEntity.setStatus(AccountRecordStatusEnum.DONE.getIndex());
        accountRecordEntity.setTime(new Date());
        accountRecordDao.update(accountRecordEntity);
        //通知
        noticeAccount(accountRecordEntity);
    }

    @Override
    public List<AccountRecordEntity> findByOrderNoAndBusType(String orderNo, Integer... busTypes) {
        return accountRecordDao.findByOrderNoAndBusType(orderNo, busTypes);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(AccountRecordVo recordVo) {
        //验证账户
        UserEntity fromUser = recordVo.getFromUser();
        UserEntity toUser = recordVo.getToUser();
        //验证账户
        userService.validateUser(fromUser, toUser);
        fromUser = userDao.findByCode(fromUser.getCode());
        toUser = userDao.findByCode(toUser.getCode());
        transfer(fromUser.getId(), toUser.getId(), recordVo.getRecord().getType(), recordVo.getRecord().getAmount(), recordVo.getRecord().getInfo());
    }

    @Autowired
    private NoticeService noticeService;

    //通知
    void noticeAccount(AccountRecordEntity recordEntity) {
        String remark = "稍后到账 ";
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            remark = "资金变动";
        }
        UserEntity fromUser = userDao.get(recordEntity.getFromUserId());
        noticeService.sendAccount(fromUser.getOpenId(), "-" + recordEntity.getAmount(), recordEntity.getFromNowAmount(), AccountTypeEnum.indexOf(recordEntity.getType()), remark + recordEntity.getInfo());
        UserEntity toUser = userDao.get(recordEntity.getToUserId());
        noticeService.sendAccount(toUser.getOpenId(), "+" + recordEntity.getAmount(), recordEntity.getToNowAmount(), AccountTypeEnum.indexOf(recordEntity.getType()), remark + recordEntity.getInfo());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountEntity decrease(Long userId, Integer type, BigDecimal amount) {

        AccountEntity accountEntity = findByUserIdAndType(userId, type);
        if (userId.equals(Const.ADMIN_ID)) {

            return accountEntity;
        }
        if (accountEntity.getAmount().compareTo(amount) < 0) {
            throw new RRException("账户余额不足");
        }
        //减少经验的时候 如果当前经验值与本身经验值不匹配  补齐
        if (type == AccountTypeEnum.EXP.getIndex()) {
            LevelEntity levelEntity = levelService.findByUserId(userId);
            if (accountEntity.getAmount().compareTo(levelEntity.getAmount()) < 0) {
                //先补齐
                accountDao.increase(userId, type, levelEntity.getAmount().subtract(accountEntity.getAmount()));
            }
        }
        accountDao.decrease(userId, type, amount);
        return accountDao.get(accountEntity.getId());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountEntity increase(Long userId, Integer type, BigDecimal amount) {
        AccountEntity accountEntity = findByUserIdAndType(userId, type);
        //增加经验的时候 如果当前经验值与本身经验值不匹配  补齐
        if (type == AccountTypeEnum.EXP.getIndex()) {
            LevelEntity levelEntity = levelService.findByUserId(userId);
            if (accountEntity.getAmount().compareTo(levelEntity.getAmount()) < 0) {
                //先补齐
                accountDao.increase(userId, type, levelEntity.getAmount().subtract(accountEntity.getAmount()));
            }
        }
        accountDao.increase(userId, type, amount);
        return accountDao.get(accountEntity.getId());
    }

    @Override
    public List<AccountEntity> findByUserId(Long userId) {
        return accountDao.findByUserId(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountRecordEntity payment(Long userId, Long recordId) {
        AccountRecordEntity recordEntity = accountRecordDao.get(recordId);
        //TODO 目前只有两种收款
        if (!recordEntity.getBus().equals(AccountRecordBusEnum.PAYMENT.getIndex()) && !recordEntity.getBus().equals(AccountRecordBusEnum.SHARE_REWARD.getIndex())) {
            throw new RRException("禁止操作!");
        }

        if (!recordEntity.getToUserId().equals(userId)) {
            throw new RRException("请勿操作他人订单!");
        }

        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            throw new RRException("已收款,请勿重复收款");
        }

        //分享利润七天后才能收
        Long tem = Const.BACK_DAY - DateUtil.getDays(recordEntity.getTime(), new Date());
        //还没有到收款时间
        if (tem > 0) {
            throw new RRException(tem + "天后收款!");
        }


        //完成转账
        doneTransfer(recordEntity);
        //如果是货款还需要进行一系列操作
        if (recordEntity.getBus().equals(AccountRecordBusEnum.PAYMENT.getIndex())) {
            //订单补货或者换货
            mallOrderService.payment(recordEntity.getInfo());
        }
//        noticeAccount(recordEntity);
        return recordEntity;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String commit(Long userId, BigDecimal amount, String noticeUrl) {
        UserEntity userEntity = userDao.get(userId);
        String orderNo = UUID.randomUUID().toString().replace("-", "");
        AccountRecordEntity recordEntity = new AccountRecordEntity(Const.ADMIN_ID, userId, AccountTypeEnum.CASH.getIndex(), amount, null, null, new Date(), orderNo, AccountRecordStatusEnum.WAIT.getIndex(), AccountRecordBusEnum.CHARGE.getIndex());
        accountRecordDao.save(recordEntity);
        String payConfig = wxPayService.createWebConfig(recordEntity.getInfo(), amount.doubleValue(), "充值", userEntity.getOpenId(), noticeUrl);
        return payConfig;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recharge(String orderNo, Integer amount) {
        AccountRecordEntity recordEntity = accountRecordDao.findByOrderNo(orderNo);
        //如果已经完成
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            return;
        }
        //付款金额正确
        if (recordEntity.getAmount().compareTo(new BigDecimal(amount / 100)) >= 0) {
            AccountEntity accountEntity = findByUserIdAndType(recordEntity.getToUserId(), recordEntity.getType());
            //转账
            increase(accountEntity.getUserId(), recordEntity.getType(), recordEntity.getAmount());
            recordEntity.setStatus(AccountRecordStatusEnum.DONE.getIndex());
            recordEntity.setToNowAmount(accountEntity.getAmount().add(recordEntity.getAmount()));
            accountRecordDao.update(recordEntity);
            //通知
            noticeAccount(recordEntity);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountEntity findByUserIdAndType(Long userId, Integer type) {
        AccountEntity accountEntity = accountDao.findByUserIdAndType(userId, type);
        if (accountEntity == null) {
            accountEntity = new AccountEntity(type, userId, BigDecimal.ZERO, BigDecimal.ZERO);
            accountDao.save(accountEntity);
        }
        return accountEntity;
    }

    @Autowired
    private LevelDao levelDao;

    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private MallActDao mallActDao;

    @Autowired
    private MallOrderDao mallOrderDao;
    @Autowired
    private AreaDao areaDao;


    /**
     * Long
     * 根据用户去查询佣金的明细
     *
     * @param userId
     * @param page
     * @param limit
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<OrderItemVo> findCommission(Long userId, Integer year, Integer month, int page, int limit) {
        PageHelper.startPage(0, 500).setOrderBy("record.time desc");
        //获取账号记录信息 TODO
        List<AccountRecordVo> accountRecordVos = this.accountRecordDao.queryByToUserId(userId, Const.ADMIN_ID, AccountTypeEnum.CASH.getIndex(), AccountRecordStatusEnum.DONE.getIndex(), year, month, "%" + Const.ORDER_NO + "%", AccountRecordBusEnum.SHARE_REWARD.getIndex(), AccountRecordBusEnum.AREA_REWARD.getIndex());

        List<OrderItemVo> orderItemVoList = new ArrayList<>();
        accountRecordVos.forEach(accountRecordVo -> {
            String accountInfo = accountRecordVo.getRecord().getInfo();
            String orderNo = accountInfo;
            if (accountInfo.equals("") || accountInfo == null) {
                return;
            }
            if (accountInfo.contains(Const.TRANSFER_REWARD)) {
                orderNo = accountInfo.split(Const.TRANSFER_REWARD)[1];
            }
            if (accountInfo.contains(Const.TRANSFER_ORDER_NO)) {
                orderNo = accountInfo.split(Const.TRANSFER_ORDER_NO)[1];
            }
            if (accountInfo.contains(Const.ORDER_NO)) {
                orderNo = accountInfo.split(Const.ORDER_NO)[1];
            }

            OrderItemVo orderItemVo = new OrderItemVo();
            orderItemVo.setRemark(orderNo);
            orderItemVo.setInfo(accountInfo);
            orderItemVo.setIncome(accountRecordVo.getRecord().getAmount());
//            this.userDao.get(accountRecordVo.getRecord().get)
            MallOrderEntity byOrderNo = this.mallOrderDao.findByOrderNo(orderNo);
            if (null != accountRecordVo.getRecord().getTime()) {
                SimpleDateFormat sdf = new SimpleDateFormat("MM/dd");
                String format = sdf.format(accountRecordVo.getRecord().getTime());
                orderItemVo.setTime(format);
            }
            if (byOrderNo == null) {
                return;
            }
            if (byOrderNo.getUserId() != null) {
                UserEntity userEntity = this.userDao.get(byOrderNo.getUserId());
                orderItemVo.setName(userEntity.getName());
            } else {
                orderItemVo.setName("   ");
            }
            orderItemVo.setOrderId(byOrderNo.getId());
            orderItemVo.setMobile(byOrderNo.getMobile());
            orderItemVoList.add(orderItemVo);
        });

        return orderItemVoList;
    }

    @Autowired
    private WxPayService wxPayService;

}
